home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / bbs / tdk_v136.zip / CHECKPAT.ASM < prev    next >
Assembly Source File  |  1992-08-23  |  20KB  |  1,046 lines

  1. ;
  2. ;    --- Version 3.3 92-08-23 12:09 ---
  3. ;
  4. ;    CHECKPAT.ASM - Utility function to check a given file/path,
  5. ;            and to resolve an incomplete path.
  6. ;            (Does not use any undocumented DOS functions.)
  7. ;
  8. ;    Public Domain Software written by
  9. ;        Thomas Wagner
  10. ;        Ferrari electronic GmbH
  11. ;        Beusselstrasse 27
  12. ;        D-1000 Berlin 21
  13. ;        Germany
  14. ;
  15. ;>e
  16. ; Assemble with
  17. ;
  18. ; tasm  /DPASCAL checkpat,checkpap           - Turbo Pascal (Tasm only), near
  19. ; tasm  /DPASCAL /DFARCALL checkpat,checkpap - Turbo Pascal (Tasm only), far
  20. ; ?asm  checkpat;                   - C, default model (small)
  21. ; ?asm  /DMODL=large checkpat               - C, large model
  22. ;
  23. ;    NOTE:    For C, change the 'model' directive below according to your
  24. ;        memory model, or define MODL=xxx on the command line.
  25. ;
  26. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  27. ;        command line, or define it here.
  28. ;
  29. ;
  30. ;   This routine accepts a file name and/or path, checks and resolves the
  31. ;   path, and splits the name into its components.
  32. ;
  33. ;   A relative path, or no path at all, is resolved to a full path
  34. ;   specification. An invalid disk drive will not cause the routine 
  35. ;   to fail.
  36. ;
  37. ;   PASCAL:
  38. ;    function checkpath (name    : string,
  39. ;                inflags : integer,
  40. ;                        drive   : string,
  41. ;                        dir     : string,
  42. ;                        fname   : string,
  43. ;                        ext     : string,
  44. ;                        fullpath: string)
  45. ;                : integer;
  46. ;   C:
  47. ;    int checkpath (char *name,     
  48. ;               int  inflags,
  49. ;                   char *drive,      
  50. ;                   char *dir,        
  51. ;                   char *fname,      
  52. ;                   char *ext,        
  53. ;                   char *fullpath);  
  54. ;
  55. ;   Parameters:
  56. ;
  57. ;    name     - Input:  file name and/or path string
  58. ;    inflags  - Input:  parameters for analysis
  59. ;               INF_NODIR: do no interpret name as directory
  60. ;    drive     - Output: drive letter, with trailing colon
  61. ;    dir     - Output: directory, with leading and trailing bakslash
  62. ;    fname     - Output: file name
  63. ;    ext     - Output: file extension, with leading dot
  64. ;    fullpath - Output: combined path
  65. ;
  66. ;    NOTE:    The input 'name' and the output 'fullpath' parameters may
  67. ;        both point to the same string. The 'fullpath' pointer will
  68. ;        only be used after completion of input parsing.
  69. ;
  70. ;    NOTE:    For Pascal, reserve one character in addition to the
  71. ;        standard maximum length for all strings, including the
  72. ;        input parameter. All strings will be zero-terminated
  73. ;        during internal processing. DO NOT pass a constant as
  74. ;        input parameter string.
  75. ;
  76. ;   Returns:
  77. ;
  78. ;    A negative value on error:
  79. ;
  80. ;        ERR_DRIVE       -1    Invalid drive
  81. ;        ERR_PATH        -2    Invalid path
  82. ;        ERR_FNAME       -3    Malformed filename
  83. ;        ERR_DRIVECHAR   -4    Illegal drive letter
  84. ;        ERR_PATHLEN     -5    Path too long
  85. ;        ERR_CRITICAL    -6    Critical error (invalid drive, drive not ready)
  86. ;
  87. ;    On error, all output strings except the drive string will be empty.
  88. ;
  89. ;    If no error occured, a positive value consisting of the bitwise OR 
  90. ;    of the following flags:
  91. ;
  92. ;        HAS_WILD        1     Filename/ext has wildcard characters
  93. ;        HAS_EXT         2     Extension specified
  94. ;        HAS_FNAME       4     Filename specified
  95. ;        HAS_PATH        8     Path specified
  96. ;        HAS_DRIVE       0x10  Drive specified
  97. ;
  98. ;            Those flags are set only if the corresponding 
  99. ;            component was given in the input string. The 
  100. ;            'drive' and 'dir' strings will always contain 
  101. ;            the resolved drive and path.
  102. ;
  103. ;        FILE_EXISTS     0x20  File exists, upper byte has attributes
  104. ;        IS_DIR        0x1000  Directory, upper byte has attributes
  105. ;
  106. ;        The file attributes returned if FILE_EXISTS or IS_DIR 
  107. ;        is set are
  108. ;            0x0100 - Read only
  109. ;            0x0200 - Hidden
  110. ;            0x0400 - System
  111. ;            0x2000 - Archive
  112. ;            0x4000 - Device
  113. ;
  114. ;<
  115. ;>d
  116. ; Assemblierung mit
  117. ;
  118. ; tasm  /DPASCAL checkpat,checkpatp          - Turbo Pascal (nur Tasm), near
  119. ; tasm  /DPASCAL /DFARCALL checkpat,checkpatp - Turbo Pascal (nur Tasm), far
  120. ; ?asm  checkpat;                    - C, default model (small)
  121. ; ?asm  /DMODL=large checkpat                - C, large model
  122. ;
  123. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  124. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  125. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  126. ;
  127. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  128. ;        angeben, oder das Symbol in dieser Quelle definieren.
  129. ;
  130. ;   Diese Routine erwartet einen Dateinamen und/oder Pfad, prüft ihn
  131. ;   und löst den Pfad auf, und teilt den Namen in seine Komponenten.
  132. ;
  133. ;   Ein relativer Pfad, oder eine fehlende Pfadangabe, wird in eine
  134. ;   absolute Pfadangabe konvertiert. Ein ungültiger Laufwerksbuchstabe
  135. ;   führt nicht zum Abbruch.
  136. ;
  137. ;   PASCAL:
  138. ;    function checkpath (name    : string,
  139. ;                inflags : integer,
  140. ;                        drive   : string,
  141. ;                        dir     : string,
  142. ;                        fname   : string,
  143. ;                        ext     : string,
  144. ;                        fullpath: string)
  145. ;                : integer;
  146. ;   C:
  147. ;    int checkpath (char *name,     
  148. ;               int  inflags,
  149. ;                   char *drive,      
  150. ;                   char *dir,        
  151. ;                   char *fname,      
  152. ;                   char *ext,        
  153. ;                   char *fullpath);  
  154. ;
  155. ;   Parameter:
  156. ;
  157. ;    name     - Input:  Filename und/oder Pfad
  158. ;    inflags  - Input:  Analyse-Parameter
  159. ;               INF_NODIR: Name nicht als Directory interpretieren
  160. ;    drive     - Output: Laufwerksbuchstabe, mit abschließendem Doppelpunkt
  161. ;    dir     - Output: Directory, mit führendem und abschließendem '\'
  162. ;    fname     - Output: Filename
  163. ;    ext     - Output: File extension, mit führendem Punkt
  164. ;    fullpath - Output: Kombinierter Pfad
  165. ;
  166. ;   Liefert:
  167. ;
  168. ;    Einen negativen Wert bei Fehler:
  169. ;
  170. ;        ERR_DRIVE       -1    Ungültiges Laufwerk
  171. ;        ERR_PATH        -2    Ungültiger Pfad
  172. ;        ERR_FNAME       -3    Fehlerhafter Dateiname
  173. ;        ERR_DRIVECHAR   -4    Illegaler Laufwerksbuchstabe
  174. ;        ERR_PATHLEN     -5    Pfad zu lang
  175. ;        ERR_CRITICAL    -6    Critical error (Illegales Laufwerk,
  176. ;                      Laufwerk nicht bereit)
  177. ;
  178. ;    Bei Fehler sind alle Ausgabestrings außer 'drive' leer.
  179. ;
  180. ;    Wenn kein Fehler auftrat einen positiven Wert der aus dem
  181. ;    bitweisen OR der folgenden Flags besteht:
  182. ;
  183. ;        HAS_WILD        1     Filename/ext enthält Wildcard-Zeichen
  184. ;        HAS_EXT         2     Extension angegeben
  185. ;        HAS_FNAME       4     Filename angegeben
  186. ;        HAS_PATH        8     Pfad angegeben
  187. ;        HAS_DRIVE       0x10  Laufwerk angegeben
  188. ;
  189. ;            Diese Flags sind nur gesetzt wenn die entsprechende 
  190. ;            Komponente im Eingabestring enthalten war. Die 
  191. ;            'drive' und 'dir' Ausgabestrings enthalten stets 
  192. ;            den aufgelösten Laufwerks- und Pfadstring.
  193. ;
  194. ;        FILE_EXISTS     0x20  Datei existiert, Attribute im oberen Byte
  195. ;        IS_DIR        0x1000  Directory, Attribute im oberen Byte
  196. ;
  197. ;        Die Dateiattribute die geliefert werden wenn FILE_EXISTS 
  198. ;        oder IS_DIR gesetzt ist sind:
  199. ;
  200. ;            0x0100 - Read only
  201. ;            0x0200 - Hidden
  202. ;            0x0400 - System
  203. ;            0x2000 - Archive
  204. ;            0x4000 - Device
  205. ;
  206. ;<
  207. ;
  208.     IFDEF    PASCAL
  209.     .model    tpascal
  210.     IFDEF    FARCALL
  211.     %out    Pascal, far calls
  212.     ELSE
  213.     %out    Pascal, near calls
  214.     ENDIF
  215. ptrsize    =    1
  216.     ELSE
  217.     IFNDEF    MODL
  218.     .model    small,c
  219.     %out    small model
  220.     ELSE
  221. %    .model    MODL,c
  222. %    %out    MODL model
  223.     ENDIF
  224. ptrsize    =    @DataSize
  225.     ENDIF
  226. ;
  227. ldds    macro    reg,var
  228.     IF    ptrsize
  229.     lds    reg,var
  230.     ELSE
  231.     mov    reg,var
  232.     ENDIF
  233.     endm
  234. ;
  235. lddsf    macro    reg,var
  236.     IF    ptrsize
  237.     lds    reg,var
  238.     ELSE
  239.     mov    ds,dseg
  240.     mov    reg,var
  241.     ENDIF
  242.     endm
  243. ;
  244. ldes    macro    reg,var
  245.     IF    ptrsize
  246.     les    reg,var
  247.     ELSE
  248.     mov    reg,var
  249.     ENDIF
  250.     endm
  251. ;
  252. ldesf    macro    reg,var
  253.     IF    ptrsize
  254.     les    reg,var
  255.     ELSE
  256.     mov    es,dseg
  257.     mov    reg,var
  258.     ENDIF
  259.     endm
  260. ;
  261.     public    checkpath
  262.     public    exists
  263. ;
  264. ERR_DRIVE    =    -1
  265. ERR_PATH    =    -2
  266. ERR_FNAME    =    -3
  267. ERR_DRIVECHAR    =    -4
  268. ERR_PATHLEN    =    -5
  269. ERR_CRITICAL    =    -6
  270. ;
  271. HAS_WILD    =    1
  272. HAS_EXT        =    2
  273. HAS_FNAME    =    4
  274. HAS_PATH    =    8
  275. HAS_DRIVE    =    10h
  276. FILE_EXISTS    =    20h
  277. IS_DIR        =    1000h
  278. ;
  279. MAXPATH        =    66
  280. ;
  281. INF_NODIR    =    1
  282. ;
  283.     IFDEF    PASCAL
  284.     .data
  285.     ELSE
  286.     IFDEF    TC_HUGE
  287.     .fardata?    checkpat_data
  288.     ELSE
  289.     .data?
  290.     ENDIF
  291.     ENDIF
  292. ;
  293. save24        label    dword
  294. sav24_off    dw    ?
  295. sav24_seg    dw    ?
  296. fail        dw    ?
  297. dfltpath    db    68 dup(?)
  298. ;
  299.     .code
  300. ;
  301. @strcpy    proc    near
  302.     lodsb
  303.     stosb
  304.     or    al,al
  305.     jnz    @strcpy
  306.     dec    di
  307.     ret
  308. @strcpy    endp
  309. ;
  310.     IFDEF    PASCAL
  311. @strlen    proc    near
  312.     push    di
  313.     inc    di
  314.     xor    ax,ax
  315.     mov    cx,-1
  316.     repne scasb
  317.     not    cx
  318.     dec    cx
  319.     pop    di
  320.     mov    es:[di],cl
  321.     ret
  322. @strlen    endp
  323.     ENDIF
  324. ;
  325. @int24_handler    proc far
  326.     push    ds
  327.     IFDEF    TC_HUGE
  328.     mov    ax,SEG checkpat_data
  329.     ELSE
  330.     IFDEF    PASCAL
  331.     mov    ax,SEG fail
  332.     ELSE
  333.     mov    ax,SEG DGROUP
  334.     ENDIF
  335.     ENDIF
  336.     mov    ds,ax
  337.     mov    fail,1
  338.     pop    ds
  339.     xor    ax,ax        ; ignore (for compatibility with DOS < 3.1)
  340.     iret
  341. @int24_handler    endp
  342. ;
  343. ;
  344.     IFDEF    PASCAL
  345.     IFDEF    FARCALL
  346. checkpath PROC far uses ds, string: dword, inflags: word, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  347.     ELSE
  348. checkpath PROC near uses ds, string: dword, inflags: word, drive: dword, path: dword, fname: dword, ext: dword, fullpath: dword
  349.     ENDIF
  350.     ELSE
  351. checkpath PROC uses ds si di, string: ptr byte, inflags: word, drive: ptr byte, path: ptr byte, fname: ptr byte, ext: ptr byte, fullpath: ptr byte
  352.     ENDIF
  353.     local    drv: word,flags:word,dseg: word
  354. ;
  355.     IFDEF    TC_HUGE
  356.     mov    ax,SEG my_data
  357.     mov    ds,ax
  358.     ENDIF
  359.     mov    dseg,ds
  360.     IFDEF    PASCAL
  361.     cld
  362.     ENDIF
  363. ;
  364. ;    save old critical error handler, install own
  365. ;
  366.     mov    ax,3524h
  367.     int    21h
  368.     mov    sav24_off,bx
  369.     mov    sav24_seg,es
  370.     mov    fail,0
  371.     mov    ax,cs
  372.     mov    ds,ax
  373.     mov    dx,offset @int24_handler
  374.     mov    ax,2524h
  375.     int    21h
  376.     mov    ds,dseg
  377. ;
  378. ;    Init output strings & flags
  379. ;
  380.     xor    ax,ax
  381.     mov    flags,ax
  382.     ldesf    di,path
  383.     IFDEF    PASCAL
  384.     stosw
  385.     ELSE
  386.     stosb
  387.     ENDIF
  388.     ldes    di,fname
  389.     IFDEF    PASCAL
  390.     stosw
  391.     ELSE
  392.     stosb
  393.     ENDIF
  394.     ldes    di,ext
  395.     IFDEF    PASCAL
  396.     stosw
  397.     ELSE
  398.     stosb
  399.     ENDIF
  400. ;
  401. ;------ Check the drive. If none was given, use current drive.
  402. ;
  403.     ldes    di,drive
  404.     IFDEF    PASCAL
  405.     inc    di
  406.     ENDIF
  407.     ldds    si,string
  408.     IFDEF    PASCAL
  409. ; for pascal, zero-terminate input string
  410.     lodsb
  411.     mov    bl,al
  412.     xor    ah,ah
  413.     mov    [si+bx],ah
  414.     ENDIF
  415. ;
  416. ; skip leading whitespace
  417. ;
  418. skip_space:
  419.     lodsb
  420.     cmp    al,' '
  421.     je    skip_space
  422.     cmp    al,09h
  423.     je    skip_space
  424.     dec    si
  425. ;
  426.     or    al,al
  427.     jz    no_drive
  428.     cmp    byte ptr 1[si],':'
  429.     je    drive_there
  430. ;
  431. no_drive:
  432.     mov    ah,19h            ; get default drive
  433.     int    21h
  434.     add    al,'A'
  435.     stosb
  436.     mov    bl,al
  437.     mov    al,':'
  438.     stosb
  439.     jmp    short check_drive
  440. ;
  441. badchar:
  442.     mov    ax,ERR_DRIVECHAR
  443.     jmp    error_exit
  444. ;
  445. drive_there:
  446.     inc    si
  447.     and    al,NOT 20h        ; convert to uppercase
  448.     cmp    al,'A'
  449.     jb    badchar
  450.     cmp    al,'A'+1fh        ; Novell allows some strange chars
  451.     ja    badchar
  452.     stosb
  453.     or    flags,HAS_DRIVE
  454.     mov    bl,al
  455.     movsb
  456. ;
  457. ;    Now check the drive for validity by getting the current directory
  458. ;    of this drive (we need it anyway later on)
  459. ;
  460. check_drive:
  461.     and    bx,1fh
  462.     mov    drv,bx
  463.     xor    al,al
  464.     stosb
  465. ;
  466.     push    ds
  467.     push    si
  468. ;
  469.     mov    ax,dseg
  470.     mov    ds,ax
  471.     mov    es,ax
  472.     mov    si,offset dfltpath+3
  473.     mov    ah,47h        ; get current directory
  474.     mov    dx,drv        ; drive number
  475.     int    21h
  476.     jc    cpath_bad
  477.     cmp    fail,0
  478.     je    cpath_good
  479. ;
  480. ;    Get dir returned an error -> the drive is invalid.
  481. ;
  482. cpath_bad:
  483.     add    sp,4
  484.     mov    ax,ERR_DRIVE
  485.     jmp    error_exit    ; can't continue with invalid drive
  486. ;
  487. ;    The drive is valid, edit the current path to include
  488. ;    leading drive letter, colon, and backslash.
  489. ;    Also, copy the path into the path output string, in case no
  490. ;    path is given in the input, and append trailing backslash to it.
  491. ;
  492. cpath_good:
  493.     mov    di,offset dfltpath
  494.     mov    ax,drv
  495.     add    al,'A'-1
  496.     stosb
  497.     mov    al,':'
  498.     stosb
  499.     mov    si,di        ; point to start of path
  500.     mov    al,'\'
  501.     stosb
  502.     ldes    di,path
  503.     IFDEF    PASCAL
  504.     inc    di
  505.     ENDIF
  506.     call    @strcpy
  507.     mov    al,'\'
  508.     cmp    byte ptr es:[di-1],al    ; root dir?
  509.     je    drive_ok        ; then no second backslash
  510.     cmp    byte ptr es:[di-1],'/'    ; forward slash also legal
  511.     je    drive_ok
  512.     stosb                ; else append backslash
  513. ;
  514. ;
  515. ;------ Drive checked, is valid. Now separate path and filename.
  516. ;
  517. drive_ok:
  518.     pop    si
  519.     pop    ds
  520.     push    si
  521.     push    di
  522.     push    es
  523.     mov    di,si
  524.     mov    ax,ds
  525.     mov    es,ax
  526. ;
  527. ;    find the end of the string
  528. ;
  529.     xor    ax,ax
  530.     mov    cx,-1
  531.     repne scasb
  532.     mov    si,di
  533.     pop    es
  534.     pop    di
  535.     not    cx
  536.     dec    cx
  537.     jnz    has_fnp        ; continue if there's more in the string
  538.     add    sp,2
  539.     stosb            ; terminate path string
  540.     jmp    check_fname    ; exit if no path or filename
  541. ;
  542. ;    search from the end for slash/backslash
  543. ;
  544. has_fnp:
  545.     sub    si,2        ; last char of string
  546.     mov    bx,5c2fh    ; the two slashes
  547.     std            ; backwards scan
  548. ;
  549. spath:
  550.     lodsb
  551.     cmp    al,bl
  552.     je    pfound
  553.     cmp    al,bh
  554.     je    pfound
  555.     loop    spath
  556. ;
  557. ;    no slash/backslash -> no path given
  558. ;
  559.     cld
  560.     pop    si
  561.     xor    cx,cx
  562.     jmp    short cfname
  563. ;
  564. longpath:
  565.     mov    ax,ERR_PATHLEN
  566.     jmp    error_exit
  567. ;
  568. ;    copy the path (note: CX has length of path including slash)
  569. ;
  570. pfound:
  571.     cld
  572.     pop    si
  573.     cmp    cx,MAXPATH
  574.     ja    longpath
  575.     or    flags,HAS_PATH        ; we have a path
  576.     ldes    di,path
  577.     IFDEF    PASCAL
  578.     inc    di
  579.     ENDIF
  580.     push    cx
  581.     rep movsb
  582.     pop    cx
  583. ;
  584. ;    check for special filenames '.' and '..', and add them to
  585. ;    the path if present.
  586. ;    The special form that adds a '.' for every level further down
  587. ;    the tree is recognized, and translated into the DOS-form '..\'
  588. ;
  589. cfname:
  590.     cmp    byte ptr [si],'.'
  591.     jne    path_finished
  592.     cmp    byte ptr [si+1],'.'
  593.     je    is_special
  594.     cmp    byte ptr [si+1],0
  595.     jne    path_finished
  596. ;
  597. is_special:
  598.     or    flags,HAS_PATH        ; we have a path
  599.     mov    bx,MAXPATH
  600.     sub    bx,cx
  601.     mov    cx,2
  602.     lodsb
  603. ;
  604. copy_special:
  605.     or    bx,bx
  606.     jz    longpath
  607.     dec    bx
  608.     stosb
  609.     lodsb
  610.     or    al,al
  611.     jz    special_finished
  612.     cmp    al,'.'
  613.     jne    badname
  614.     loop    copy_special
  615. ;
  616. add_special:
  617.     sub    bx,3
  618.     jle    longpath
  619.     mov    al,'\'
  620.     stosb
  621.     mov    al,'.'
  622.     stosb
  623.     stosb
  624.     lodsb
  625.     or    al,al
  626.     jz    special_finished
  627.     cmp    al,'.'
  628.     jne    badname
  629.     jmp    add_special
  630. ;
  631. badname:
  632.     mov    ax,ERR_FNAME
  633.     jmp    error_exit
  634. ;
  635. special_finished:
  636.     dec    si
  637.     mov    al,'\'
  638.     stosb
  639. ;
  640. ;    now copy the filename and extension (limited to 8/3 chars)
  641. ;
  642. path_finished:
  643.     xor    al,al            ; terminate path
  644.     stosb
  645. ;
  646.     mov    bx,2a3fh        ; the two wildcards '*' and '?'
  647.     ldes    di,fname
  648.     IFDEF    PASCAL
  649.     inc    di
  650.     ENDIF
  651.     mov    cx,8            ; max 8 for name
  652. ;
  653. cfnloop:
  654.     lodsb
  655.     or    al,al            ; end of string?
  656.     jz    cfndot
  657.     cmp    al,'.'
  658.     je    cfndot
  659.     jcxz    cfnloop            ; skip if 8 chars copied
  660.     stosb
  661.     dec    cx
  662.     or    flags,HAS_FNAME
  663.     cmp    al,bl            ; check for wildcards    
  664.     je    fnwild
  665.     cmp    al,bh
  666.     jne    cfnloop
  667. ;
  668. fnwild:
  669.     or    flags,HAS_WILD
  670.     jmp    cfnloop
  671. ;
  672. cfndot:
  673.     mov    ah,al            ; save terminator (0 or '.')
  674.     xor    al,al
  675.     stosb                ; terminate filename
  676.     or    ah,ah
  677.     jz    no_ext            ; jump if at end of string
  678. ;
  679. ;    extension present, copy it.
  680. ;
  681.     or    flags,HAS_EXT
  682.     ldes    di,ext
  683.     IFDEF    PASCAL
  684.     inc    di
  685.     ENDIF
  686.     mov    cx,3
  687.     mov    al,ah
  688.     stosb                ; store '.' as first ext char
  689. ;
  690. cextloop:
  691.     lodsb
  692.     or    al,al
  693.     jz    cextend
  694.     stosb
  695.     cmp    al,bl            ; check for wildcards    
  696.     je    extwild
  697.     cmp    al,bh
  698.     jne    cextcont
  699. ;
  700. extwild:
  701.     or    flags,HAS_WILD
  702. ;
  703. cextcont:
  704.     loop    cextloop
  705. ;
  706. cextend:
  707.     xor    al,al
  708.     stosb                ; terminate extension
  709. ;
  710. ;
  711. no_ext:
  712.     test    flags,HAS_PATH
  713.     jz    check_fname
  714. ;
  715. ;    A path was specified, check it:
  716. ;    Change the current directory to the one specified. 
  717. ;    If valid, read back the new directory string 
  718. ;    (which has '.' and '..' resolved).
  719. ;    In any case, restore the current directory.
  720. ;
  721.     ldes    di,fullpath    ; make path string from drive and path
  722.     IFDEF    PASCAL
  723.     inc    di
  724.     ENDIF
  725.     ldds    si,drive
  726.     IFDEF    PASCAL
  727.     inc    si
  728.     ENDIF
  729.     call    @strcpy
  730.     ldds    si,path
  731.     IFDEF    PASCAL
  732.     inc    si
  733.     ENDIF
  734.     call    @strcpy
  735.     cmp    byte ptr es:[di-2],':'    ; root dir ?
  736.     je    no_slstrip        ; then don't strip backslash
  737.     mov    byte ptr es:[di-1],0    ; else remove trailing '\'
  738. ;
  739. no_slstrip:
  740.     xor    cx,cx        ; cx is 'path ok' flag (init to not ok)
  741.     ldds    dx,fullpath
  742.     IFDEF    PASCAL
  743.     inc    dx
  744.     ENDIF
  745.     ldes    di,path
  746.     IFDEF    PASCAL
  747.     inc    di
  748.     ENDIF
  749.     mov    ah,3bh        ; change current directory
  750.     int    21h
  751.     mov    ds,dseg
  752.     jc    rest_path    ; skip dir reading if invalid
  753.     cmp    fail,0
  754.     jne    rest_path
  755. ;
  756. ;    read back path
  757. ;
  758.     ldds    si,path
  759.     IFDEF    PASCAL
  760.     inc    si
  761.     ENDIF
  762.     inc    si        ; leave space for leading '\'
  763.     mov    ah,47h        ; get current directory
  764.     mov    dx,drv        ; drive number
  765.     int    21h
  766.     mov    ds,dseg
  767.     jc    rest_path    ; shouldn't happen, but...
  768.     cmp    fail,0
  769.     jne    rest_path
  770. ;
  771.     mov    byte ptr es:[di],'\'    ; prefix with '\'
  772.     xor    ax,ax
  773.     mov    cx,-1
  774.     repne scasb            ; find end of string
  775.     not    cx
  776.     cmp    cx,2
  777.     je    rest_path        ; don't append trailing '\' if root
  778.     mov    byte ptr es:[di-1],'\'
  779.     stosb                ; terminate
  780. ;
  781. rest_path:
  782.     mov    dx,offset dfltpath
  783.     mov    ah,3bh
  784.     int    21h
  785. ;
  786. ;    was the path ok?
  787. ;
  788.     or    cx,cx
  789.     jnz    check_fname
  790. ;
  791. ;    exit if not
  792. ;
  793.     mov    ax,ERR_PATH
  794.     jmp    error_exit
  795. ;
  796. ;    the path was ok, now check the filename if it doesn't contain
  797. ;    wildcard chars.
  798. ;
  799. check_fname:
  800.     test    flags,HAS_WILD
  801.     jz    checkfn1
  802.     jmp    ready
  803. ;
  804. checkfn1:
  805.     ldesf    di,fullpath    ; make full path string
  806.     IFDEF    PASCAL
  807.     inc    di
  808.     ENDIF
  809.     lddsf    si,drive
  810.     IFDEF    PASCAL
  811.     inc    si
  812.     ENDIF
  813.     call    @strcpy
  814.     ldds    si,path
  815.     IFDEF    PASCAL
  816.     inc    si
  817.     ENDIF
  818.     call    @strcpy
  819.     test    flags,HAS_FNAME OR HAS_EXT
  820.     jnz    checkfn2
  821. ;
  822. ;    No filename, get the attribute of the directory
  823. ;
  824.     or    flags,IS_DIR
  825.     dec    di
  826.     mov    byte ptr es:[di],0    ; clear trailing '\'
  827.     dec    di
  828.     cmp    byte ptr es:[di],':'    ; root dir?
  829.     je    no_dirchk        ; then don't get attribute
  830.     ldds    dx,fullpath
  831.     IFDEF    PASCAL
  832.     inc    dx
  833.     ENDIF
  834.     mov    ax,4300h    ; get attribute
  835.     int    21h
  836.     mov    ds,dseg
  837.     jc    no_attrib    ; shouldn't happen
  838.     cmp    fail,0
  839.     jne    no_attrib
  840.     mov    ax,flags
  841.     mov    ah,cl
  842.     and    ah,7fh
  843.     mov    flags,ax
  844. no_dirchk:
  845.     jmp    ready
  846. ;
  847. no_attrib:
  848.     mov    ax,ERR_PATH
  849.     jmp    error_exit
  850. ;
  851. checkfn2:
  852.     ldds    si,fname
  853.     IFDEF    PASCAL
  854.     inc    si
  855.     ENDIF
  856.     call    @strcpy
  857.     ldds    si,ext
  858.     IFDEF    PASCAL
  859.     inc    si
  860.     ENDIF
  861.     call    @strcpy
  862. ;
  863.     mov    ah,2fh        ; get current DTA
  864.     int    21h        ; ES:BX has current DTA
  865.     push    bx
  866.     push    es
  867. ;
  868.     mov    ds,dseg
  869.     mov    dx,offset dfltpath
  870.     mov    ah,1ah        ; set DTA
  871.     int    21h
  872. ;
  873.     ldds    dx,fullpath
  874.     IFDEF    PASCAL
  875.     inc    dx
  876.     ENDIF
  877.     mov    cx,10110B    ; search all except label
  878.     mov    ah,4eh        ; search for first
  879.     int    21h
  880.     mov    ds,dseg
  881.     jc    no_file
  882.     cmp    fail,0
  883.     jne    no_file
  884. ;
  885.     mov    ax,flags
  886.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  887.     test    ah,10h        ; subdirectory?
  888.     jz    no_subdir
  889. ;
  890. ;    The filename specifies a subdirectory. Append it to the path.
  891. ;
  892.     test    inflags,INF_NODIR
  893.     jnz    no_file
  894.     ldesf    di,path
  895.     IFDEF    PASCAL
  896.     inc    di
  897.     ENDIF
  898.     mov    cx,-1
  899.     xor    ax,ax
  900.     repne scasb
  901.     dec    di
  902.     mov    si,offset dfltpath+1eh
  903.     call    @strcpy
  904.     mov    al,'\'
  905.     stosb
  906.     xor    al,al
  907.     stosb
  908.     ldes    di,fname
  909.     IFDEF    PASCAL
  910.     inc    di
  911.     ENDIF
  912.     stosb
  913.     ldes    di,ext
  914.     IFDEF    PASCAL
  915.     inc    di
  916.     ENDIF
  917.     stosb
  918.     mov    ax,flags
  919.     mov    ah,dfltpath+15h    ; file attributes into upper byte of flags
  920.     and    ah,7fh        ; make sure it's positive
  921.     and    al,NOT (HAS_FNAME OR HAS_EXT)
  922.     or    al,HAS_PATH
  923.     mov    flags,ax
  924.     jmp    short no_file
  925. ;
  926. no_subdir:
  927.     or    al,FILE_EXISTS
  928.     and    ah,7fh        ; make sure it's positive
  929.     mov    flags,ax
  930. ;
  931. no_file:
  932.     pop    ds
  933.     pop    dx
  934.     mov    ah,1ah
  935.     int    21h        ; restore DTA
  936. ;
  937. ready:
  938.     ldesf    di,fullpath    ; make full path string
  939.     IFDEF    PASCAL
  940.     inc    di
  941.     ENDIF
  942.     lddsf    si,drive
  943.     IFDEF    PASCAL
  944.     inc    si
  945.     ENDIF
  946.     call    @strcpy
  947.     ldds    si,path
  948.     IFDEF    PASCAL
  949.     inc    si
  950.     ENDIF
  951.     call    @strcpy
  952.     ldds    si,fname
  953.     IFDEF    PASCAL
  954.     inc    si
  955.     ENDIF
  956.     call    @strcpy
  957.     ldds    si,ext
  958.     IFDEF    PASCAL
  959.     inc    si
  960.     ENDIF
  961.     call    @strcpy
  962.     mov    ds,dseg
  963.     mov    ax,flags
  964. ;
  965. error_exit:
  966.     mov    ds,dseg
  967.     cmp    fail,0
  968.     je    nofail
  969.     mov    ax,ERR_CRITICAL
  970. ;
  971. nofail:
  972.     push    ax
  973.     cmp    ax,0
  974.     jge    no_error
  975.     ldesf    di,fullpath
  976.     mov    word ptr es:[di],0
  977. ;
  978. no_error:
  979.     lds    dx,save24
  980.     mov    ax,2524h
  981.     int    21h
  982.     IFDEF    PASCAL
  983.     ldesf    di,drive
  984.     call    @strlen
  985.     ldes    di,path
  986.     call    @strlen
  987.     ldes    di,fname
  988.     call    @strlen
  989.     ldes    di,ext
  990.     call    @strlen
  991.     ldes    di,fullpath
  992.     call    @strlen
  993.     ENDIF
  994.     pop    ax
  995. ;
  996.     ret
  997. ;
  998. checkpath endp
  999. ;
  1000. ;
  1001. ;e Returns TRUE if a file with name 'fname' exists.
  1002. ;d Liefert TRUE wenn eine Datei mit dem Namen 'fname' existiert.
  1003. ;
  1004.     IFDEF    PASCAL
  1005.     IFDEF    FARCALL
  1006. exists    PROC far uses ds, fname: dword
  1007.     ELSE
  1008. exists    PROC near uses ds, fname: dword
  1009.     ENDIF
  1010.     ELSE
  1011. exists    PROC    uses ds, fname: ptr byte
  1012.     ENDIF
  1013. ;
  1014.     IFDEF    TC_HUGE
  1015.     mov    ax,SEG my_data
  1016.     mov    ds,ax
  1017.     ENDIF
  1018. ;
  1019.     IFDEF    PASCAL
  1020.     ldds    si,fname
  1021. ; for pascal, zero-terminate input string
  1022.     lodsb
  1023.     mov    bl,al
  1024.     xor    bh,bh
  1025.     mov    [si+bx],bh
  1026.     mov    dx,si
  1027.     ELSE
  1028.     ldds    dx,fname
  1029.     ENDIF
  1030. ;
  1031.     mov    ax,4300h    ; get file attributes
  1032.     int    21h
  1033.     mov    ax,0
  1034.     jc    exists_end
  1035.     test    cx,10h        ; directory?
  1036.     jnz    exists_end
  1037.     inc    ax
  1038. ;
  1039. exists_end:
  1040.     ret
  1041. ;
  1042. exists    endp
  1043. ;
  1044.     end
  1045.  
  1046.